Skip to main content

SSH Key Login Only

SSH key login only means configuring OpenSSH so that users can authenticate using public key cryptography and cannot authenticate using passwords or interactive challenge methods. This is one of the most effective SSH hardening steps because it removes an entire class of brute-force and credential-stuffing attacks against password authentication.

Background and history

SSH originally supported password authentication for convenience, but internet-exposed servers quickly became targets for automated brute-force attempts. Key-based authentication became the standard secure approach because it relies on cryptographic proof instead of a shared secret typed over a network session. Modern hardening baselines typically disable password authentication entirely and rely on key pairs managed by administrators.

Adoption and where it’s commonly used

Common in:

  • VPS and cloud servers with public SSH access
  • Production web servers (WordPress stacks) where SSH is a high-value target
  • Environments using configuration management and CI/CD (deploy keys, forced commands)
  • Bastion host patterns where access is tightly controlled

Maintained by

  • Maintained by the OpenSSH project community.

Best when to use

  • The server is reachable from the internet and receives frequent SSH scans.
  • You have reliable key management for all administrators.
  • You want to eliminate password brute-force risk entirely.
  • You plan to disable root SSH login and rely on sudo-capable admin users.

Not suitable when

  • You cannot ensure every admin has working keys and a recovery path.
  • You depend on password-based automation or legacy tooling that cannot use keys.
  • You do not have console/serial access for recovery and cannot risk lockout.

Compatibility notes

  • Settings are in /etc/ssh/sshd_config or /etc/ssh/sshd_config.d/*.conf depending on distro.

  • System service name differs:

    • Debian/Ubuntu: ssh
    • RHEL-based: sshd
  • Some systems use additional auth mechanisms (PAM, keyboard-interactive). Disabling passwords alone may not fully disable interactive authentication unless you disable keyboard-interactive as well.

  • Ensure your firewall allows your SSH port before making changes.

Lockout risk

Do not disable password authentication until you have confirmed that key-based login works in a separate SSH session for at least one sudo-capable user. Keep your original session open until verification is complete.

Concepts and how it works

  • Your workstation holds a private key (keep it secret).
  • The server stores your public key in ~/.ssh/authorized_keys.
  • During login, the server verifies you control the private key without sending it over the network.

Prerequisites

  • An existing SSH session to the server
  • A sudo-capable non-root user (recommended)
  • Provider console/serial access or another recovery path
  • OpenSSH server installed and running

Step 1: Create an SSH key on your workstation

Choose one of these key types. Ed25519 is recommended on modern systems.

ssh-keygen -t ed25519 -a 64 -f ~/.ssh/id_ed25519

Generate an RSA key (legacy compatibility)

Use RSA only when Ed25519 is not supported by your environment.

ssh-keygen -t rsa -b 4096 -a 64 -f ~/.ssh/id_rsa
Passphrases

Use a passphrase for your private key on laptops and developer machines. It reduces impact if the key file is copied. For automation keys, use restricted accounts and narrow permissions.

Step 2: Install the public key on the server

Default port:

ssh-copy-id user@your_server_ip

Custom SSH port:

ssh-copy-id -p 2581 user@your_server_ip

Option B: Manual install (works everywhere)

On your workstation, print the public key:

cat ~/.ssh/id_ed25519.pub

On the server, as the target user:

mkdir -p ~/.ssh
chmod 700 ~/.ssh
nano ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

Paste the public key on its own line into authorized_keys.

Verify permissions:

ls -ld ~/.ssh
ls -l ~/.ssh/authorized_keys

Step 3: Test key-based login before changing the server

From your workstation, open a new terminal and test:

Default port:

ssh user@your_server_ip

Custom port:

ssh -p 2581 user@your_server_ip

Force key use (debug-friendly):

ssh -i ~/.ssh/id_ed25519 -p 2581 user@your_server_ip

If it fails, use verbose mode:

ssh -vvv -p 2581 user@your_server_ip

Step 4: Configure OpenSSH to allow keys and disable passwords

Prefer using drop-in configs when supported.

Create a hardening drop-in

Create /etc/ssh/sshd_config.d/10-key-auth.conf:

sudo tee /etc/ssh/sshd_config.d/10-key-auth.conf >/dev/null <<'EOF'
# Key-based authentication only
PubkeyAuthentication yes

# Disable password and interactive auth
PasswordAuthentication no
KbdInteractiveAuthentication no
ChallengeResponseAuthentication no

# Optional: reduce auth noise
MaxAuthTries 3
LoginGraceTime 30
EOF

If your system does not use sshd_config.d, edit /etc/ssh/sshd_config directly and place the same directives near the end of the file.

ChallengeResponseAuthentication compatibility

Some OpenSSH versions ignore ChallengeResponseAuthentication in favor of KbdInteractiveAuthentication. Setting both is safe and reduces ambiguity across distributions.

Step 5: Validate configuration and reload SSH safely

Validate config syntax:

sudo sshd -t

If the command returns no output, syntax validation passed.

Reload the SSH daemon (preferred over restart):

sudo systemctl reload ssh 2>/dev/null || sudo systemctl reload sshd

Keep your original SSH session open.

Step 6: Confirm password authentication is disabled

Open a second session and verify:

  • key login still works
  • password login fails

Confirm key login works

ssh -p 2581 user@your_server_ip

Confirm passwords are rejected

From a different machine without your key, or by forcing password auth attempt:

ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no -p 2581 user@your_server_ip

Expected: authentication fails.

Optional: Harden allowed users and root login

Key-only is strongest when paired with reduced login surface.

Restrict which users can SSH

Create /etc/ssh/sshd_config.d/20-allow-users.conf:

sudo tee /etc/ssh/sshd_config.d/20-allow-users.conf >/dev/null <<'EOF'
AllowUsers adminuser opsuser
EOF

Disable root SSH login

Create /etc/ssh/sshd_config.d/30-no-root.conf:

sudo tee /etc/ssh/sshd_config.d/30-no-root.conf >/dev/null <<'EOF'
PermitRootLogin no
EOF

Validate and reload:

sudo sshd -t
sudo systemctl reload ssh 2>/dev/null || sudo systemctl reload sshd

Troubleshooting

Key login fails after disabling passwords

Common causes:

  • Wrong file permissions on ~/.ssh or authorized_keys
  • Wrong username or connecting to the wrong host/port
  • AllowUsers/AllowGroups excludes the user
  • Wrong key used by client (multiple keys loaded)

Server-side checks:

sudo ls -ld /home/<user> /home/<user>/.ssh 2>/dev/null || true
sudo ls -l /home/<user>/.ssh/authorized_keys 2>/dev/null || true
sudo sshd -T | grep -E '^(pubkeyauthentication|passwordauthentication|kbdinteractiveauthentication|permitrootlogin|allowusers|allowgroups)'

Client-side checks:

ssh -vvv -p 2581 user@your_server_ip
ssh-add -l 2>/dev/null || true

SSH reload fails

sudo sshd -t
sudo journalctl -u ssh -n 200 --no-pager 2>/dev/null || sudo journalctl -u sshd -n 200 --no-pager

Locked out

Recovery requires provider console/serial access. Revert the last change:

  • remove or edit the drop-in file(s)
  • validate with sshd -t
  • reload the service

Example revert:

sudo rm -f /etc/ssh/sshd_config.d/10-key-auth.conf
sudo sshd -t
sudo systemctl reload ssh 2>/dev/null || sudo systemctl reload sshd
Always keep a recovery path

Before applying SSH authentication changes on a remote VPS, ensure you can access a provider console session to revert changes if needed.

Security notes

  • Store private keys securely and avoid copying them to servers.
  • Use separate keys per administrator for accountability.
  • Remove keys immediately when an operator leaves.
  • For automation, prefer restricted keys (command=, from=, no-pty) and dedicated accounts.

Example of a restricted key entry (advanced):

from="203.0.113.10",no-agent-forwarding,no-port-forwarding,no-pty,no-user-rc,command="/usr/local/bin/deploy.sh" ssh-ed25519 AAAA... comment

Quick reference

GoalCommand
-
Generate key (Ed25519)ssh-keygen -t ed25519 -a 64
Copy key to serverssh-copy-id -p 2581 user@host
Test key loginssh -p 2581 user@host
Validate sshd configsudo sshd -t
Reload sshdsudo systemctl reload ssh || sudo systemctl reload sshd
Force password attempt (should fail)ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no user@host